﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using System.Collections.ObjectModel;
using System.Xml.Serialization;
using System.Windows.Input;
using CodeWriterHelper.Commands;

namespace CodeWriterHelper.Objects
{
    [Serializable]
    public class WriterOptions : INotifyPropertyChanged
    {
        private string _name = Guid.NewGuid().ToString();
        public string Name
        {
            get
            {
                return _name;
            }
            set
            {
                _name = value;
                RaisePropertyChanged("Name");
            }
        }

        private string _linePrefix = null;
        public string LinePrefix
        {
            get
            {
                return _linePrefix;
            }
            set
            {
                _linePrefix = value;
                RaisePropertyChanged("LinePrefix");
            }
        }

        private string _lineSuffix = null;
        public string LineSuffix
        {
            get
            {
                return _lineSuffix;
            }
            set
            {
                _lineSuffix = value;
                RaisePropertyChanged("LineSuffix");
            }
        }

        private string _emptyRow = null;
        public string EmptyRow
        {
            get
            {
                return _emptyRow;
            }
            set
            {
                _emptyRow = value;
                RaisePropertyChanged("EmptyRow");
            }
        }

        private bool _useTabTokens = true;
        public bool UseTabTokens
        {
            get
            {
                return _useTabTokens;
            }
            set
            {
                _useTabTokens = value;
                RaisePropertyChanged("UseTabTokens");
            }
        }

        private bool _autoUpdate = true;
        public bool AutoUpdate
        {
            get
            {
                return _autoUpdate;
            }
            set
            {
                _autoUpdate = value;
                RaisePropertyChanged("AutoUpdate");
            }
        }

        private string _addTab = null;
        public string AddTab
        {
            get
            {
                return _addTab;
            }
            set
            {
                _addTab = value;
                RaisePropertyChanged("AddTab");
            }
        }

        private string _removeTab = null;
        public string RemoveTab
        {
            get
            {
                return _removeTab;
            }
            set
            {
                _removeTab = value;
                RaisePropertyChanged("RemoveTab");
            }
        }

        private string _originalText = string.Empty;
        [XmlIgnore]
        public string OriginalText
        {
            get
            {
                return _originalText;
            }
            set
            {
                _originalText = value;
                RaisePropertyChanged("OriginalText");
            }
        }

        private string _resultText = null;
        [XmlIgnore]
        public string ResultText
        {
            get
            {
                return _resultText;
            }
            set
            {
                _resultText = value;
                RaisePropertyChanged("ResultText");
            }
        }

        private ObservableCollection<CodeReplaceEntry> _replaceEntries = null;
        public ObservableCollection<CodeReplaceEntry> ReplaceEntries
        {
            get
            {
                if (_replaceEntries == null)
                {
                    _replaceEntries = new ObservableCollection<CodeReplaceEntry>();
                }

                return _replaceEntries;
            }
            set
            {
                _replaceEntries = value;
                RaisePropertyChanged("ReplaceEntries");
            }
        }

        private ICommand _removeConfigCommand = null;
        [XmlIgnore]
        public ICommand RemoveConfigCommand
        {
            get
            {
                if (_removeConfigCommand == null)
                {
                    _removeConfigCommand = new DelegateCommand(arg =>
                    {
                        RaiseRemoveRequest();
                    });
                }

                return _removeConfigCommand;
            }
            private set
            {
                if (_removeConfigCommand != value)
                {
                    _removeConfigCommand = value;
                    this.RaisePropertyChanged("RemoveConfigCommand");
                }
            }
        }

        private string[] lineSeparators = new string[] { "\r\n" };
        public void buildTransformerCode()
        {
            string replacedCode = OriginalText;

            foreach (CodeReplaceEntry entry in ReplaceEntries)
            {
                replacedCode = replacedCode.Replace(entry.StringToReplace, entry.NewString);
            }

            string[] lines = replacedCode.Split(lineSeparators, StringSplitOptions.None);

            StringBuilder builder = new StringBuilder();
            int currentTabCount = 0;
            int numberOfTabs = 0;
            string trimmedLine = string.Empty;

            foreach (string line in lines)
            {
                if (!string.IsNullOrWhiteSpace(EmptyRow))
                {
                    // Empty Line
                    if (string.IsNullOrWhiteSpace(line))
                    {
                        builder.AppendLine(EmptyRow);
                        continue;
                    }
                }

                if (UseTabTokens)
                {
                    // Tabs control
                    numberOfTabs = GetNumberOfTabs(line);

                    while (numberOfTabs > currentTabCount)
                    {
                        builder.AppendLine(AddTab);
                        currentTabCount++;
                    }

                    while (numberOfTabs < currentTabCount)
                    {
                        builder.AppendLine(RemoveTab);
                        currentTabCount--;
                    }
                }

                // removal of tabs from beginning of line
                trimmedLine = line;
                foreach (string separator in tabSeparators)
                {
                    while (trimmedLine.StartsWith(separator))
                    {
                        trimmedLine = trimmedLine.Substring(separator.Length);
                    }
                }

                builder.AppendLine(string.Format("{0}{1}{2}", LinePrefix, trimmedLine, LineSuffix));
            }

            ResultText = builder.ToString();
        }

        private string[] tabSeparators = new string[] { "\t", "    " };
        public int GetNumberOfTabs(string code)
        {
            string[] parts = code.Split(tabSeparators, StringSplitOptions.None);
            return parts.Length - 1;
        }

        public event EventHandler RemoveRequest;
        public void RaiseRemoveRequest()
        {
            if (RemoveRequest != null)
            {
                RemoveRequest(this, EventArgs.Empty);
            }
        }

        #region PropertyChanged

        public event PropertyChangedEventHandler PropertyChanged;
        public void RaisePropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        #endregion PropertyChanged
    }
}
